package http;

import core.ByteBuf;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//http报文
public class HttpMessage {

    public static final String[] methods={"GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD", "OPTIONS", "TRACE", "PATCH"};

    public static final String newLine="\r\n";

    public static final int maxsize=10*1024*1024;

    public static final Charset charset=StandardCharsets.ISO_8859_1;

    public String httpVersion="1.1";

    public Map<String, List<String>> header=new HashMap<>();

    public ByteBuf byteBuf=new ByteBuf();

    public static boolean checkHttpMessage(byte[] bytes,Charset charset){

        String data=new String(bytes,charset);

        data=clearMessage(data);

        if (data.startsWith("HTTP/")) return true;
        if (checkMethod(data)) return true;

        //分析第一行结尾
        int pos = data.indexOf("\r\n");
        if (pos == -1)  return false;

        String firstLine=data.substring(0,pos);
        //根据http结束符判断
        return firstLine.contains(" HTTP/");
    }

    public static boolean checkMethod(String str){
        for (String s:methods
        ) {
            if (str.startsWith(s)) return true;
        }

        return false;
    }

    public static  void getHeaderField(String header,Map<String, List<String>> map){

        String[] lines=header.split(newLine);
        for (String line:lines
        ) {
            int pos=line.indexOf(": ");
            if (pos!=-1) {
                //不区分大小写，统一小写
                String key=line.substring(0,pos).toLowerCase();
                if (!map.containsKey(key)){
                    map.put(key,new ArrayList<>());
                }
                map.get(key).add(line.substring(pos+newLine.length()));
            }
        }
    }

    public static int getHttpLength(byte[] bytes,Charset charset){

        String data=new String(bytes,charset);

        data=clearMessage(data);

        int pos=data.indexOf(newLine+newLine);
        if (pos==-1) return -1;

        if (checkNoContent(data)) return 0;

        String header=data.substring(0, pos);
        String content=data.substring(pos+2*newLine.length());

        Map<String,List<String>> map=new HashMap<>();
        getHeaderField(header,map);

        return parseContent(map,content,charset,null);
    }

    public static int parseContent(Map<String, List<String>> header,String content,Charset charset,ByteBuf buf){

        int remainSize=0;
        byte[] bytes=content.getBytes(charset);
        if (header.containsKey("content-length")) {
            //String value=map.get("content-length").get(0); //第一个
            String value=header.get("content-length").stream().reduce((first, second) -> second).orElse("0"); //最后一个
            int nContentLen=Integer.parseInt(value);
            if (buf!=null) buf.put(bytes,0,nContentLen);
            remainSize=bytes.length - nContentLen;
        }
        else if (header.containsKey("transfer-encoding")) {
            int pStart = 0;
            do
            {
                int pEnd=content.indexOf(newLine,pStart);
                if (pEnd == -1) {
                    return  -1;
                }
                String hexString=new String(bytes,pStart,pEnd,charset);
                int size=Integer.parseInt(hexString, 16);
                if (size==0)
                {
                    remainSize=bytes.length -pEnd;
                    break;
                }
                if (pEnd + 2 + size < bytes.length)
                {
                    pEnd += 2;
                    if (buf!=null) buf.put(bytes, pEnd, size);
                    pStart = pEnd + size + 2;
                }
                else
                {
                    return  -1;
                }
            } while (true);

        }

        return remainSize;
    }

    public static String trimString(String data,String str){
        int pos=0;
        while (data.startsWith(str,pos)){
            pos += str.length();
        }

        return data.substring(pos);
    }

    public static String clearMessage(String data){
        //parse 1k
        data=trimString(data,"HTTP/1.1 100 Continue\r\n\r\n");
        //parse newline
        data=trimString(data,newLine);

        return data;
    }

    public static String getListLast(List<String> list){
        if (list==null || list.isEmpty())
            return "";
        else
            return list.stream().reduce((first, second) -> second).orElse(""); //最后一个
    }

    public static boolean checkNoContent(String data){
        return data.startsWith("GET ")||data.startsWith("HEAD ");
    }

    public static ByteBuf getBuf(String data,Charset charset){
        ByteBuf buf=new ByteBuf();
        buf.put(data.getBytes(charset));
        return buf;
    }

    public ByteBuf getBuf(String data){
        return getBuf(data,charset);
    }

    public String getHeader(String key){
        //统一小写
        return getListLast(header.get(key.toLowerCase()));
    }

    public void setHeader(String key,String value){
        //不区分大小写，统一小写
        String lowerKey=key.toLowerCase();
        if (header.containsKey(lowerKey)){
            header.get(lowerKey).add(value);
        }
        else {
            header.put(lowerKey,new ArrayList<>(List.of(value)));
        }
    }

    public boolean checkHttpMessage(byte[] bytes){
        return checkHttpMessage(bytes,charset);
    }

}
